home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / plasma.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-06-04  |  20.2 KB  |  842 lines

  1. /*
  2.  * This is a plugin for the GIMP.
  3.  *
  4.  * Copyright (C) 1996 Stephen Norris
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  *
  20.  */
  21.  
  22. /*
  23.  * This plug-in produces plasma fractal images. The algorithm is losely
  24.  * based on a description of the fractint algorithm, but completely
  25.  * re-implemented because the fractint code was too ugly to read :)
  26.  *
  27.  * Please send any patches or suggestions to me: srn@flibble.cs.su.oz.au.
  28.  */
  29.  
  30. /*
  31.  * TODO:
  32.  *    - The progress bar sucks.
  33.  *    - It writes some pixels more than once.
  34.  */
  35.  
  36. /* Version 1.01 */
  37.  
  38. /*
  39.  * Ported to GIMP Plug-in API 1.0
  40.  *    by Eiichi Takamori <taka@ma1.seikyou.ne.jp>
  41.  *
  42.  * $Id: plasma.c,v 1.26.2.3 2002/05/14 17:14:14 bolsh Exp $
  43.  *
  44.  * A few functions names and their order are changed :)
  45.  * Plasma implementation almost hasn't been changed.
  46.  *
  47.  * Feel free to correct my WRONG English, or to modify Plug-in Path,
  48.  * and so on. ;-)
  49.  *
  50.  * Version 1.02 
  51.  *
  52.  * May 2000
  53.  * tim copperfield [timecop@japan.co.jp]
  54.  * Added dynamic preview mode.
  55.  *
  56.  */
  57.  
  58. #include "config.h"
  59.  
  60. #include <stdlib.h>
  61. #include <stdio.h>
  62. #include <string.h>
  63. #include <time.h>  /* For random seeding */
  64.  
  65. #include <gtk/gtk.h>
  66.  
  67. #include <libgimp/gimp.h>
  68. #include <libgimp/gimpui.h>
  69.  
  70. #include "libgimp/stdplugins-intl.h"
  71.  
  72.  
  73. /* Some useful macros */
  74.  
  75. #define ENTRY_WIDTH      75
  76. #define SCALE_WIDTH     128
  77. #define TILE_CACHE_SIZE  32
  78. #define PREVIEW_SIZE    128
  79.  
  80. typedef struct
  81. {
  82.   gint     seed;
  83.   gdouble  turbulence;
  84.   /* Interface only */
  85.   gboolean timeseed;
  86. } PlasmaValues;
  87.  
  88. typedef struct
  89. {
  90.   gint run;
  91. } PlasmaInterface;
  92.  
  93. /*
  94.  * Function prototypes.
  95.  */
  96.  
  97. static void    query    (void);
  98. static void    run    (gchar   *name,
  99.              gint    nparams,
  100.              GimpParam  *param,
  101.              gint    *nreturn_vals,
  102.              GimpParam  **return_vals);
  103.  
  104. static GtkWidget *preview_widget         (GimpImageType drawable_type);
  105. static gint    plasma_dialog            (GimpDrawable *drawable,
  106.                           GimpImageType drawable_type);
  107. static void     plasma_ok_callback       (GtkWidget *widget, 
  108.                       gpointer   data);
  109. static void     plasma_seed_changed_callback (GimpDrawable *drawable,
  110.                                               gboolean    preview_mode);
  111.  
  112. static void    plasma         (GimpDrawable *drawable, 
  113.                   gboolean   preview_mode);
  114. static void     random_rgb   (guchar    *d);
  115. static void     add_random   (guchar    *d,
  116.                   gint       amnt);
  117. static void     init_plasma  (GimpDrawable *drawable, 
  118.                   gboolean   preview_mode);
  119. static void     provide_tile (GimpDrawable *drawable,
  120.                   gint       col,
  121.                   gint       row);
  122. static void     end_plasma   (GimpDrawable *drawable,
  123.                   gboolean   preview_mode);
  124. static void     get_pixel    (GimpDrawable *drawable,
  125.                   gint       x,
  126.                   gint       y,
  127.                   guchar    *pixel,
  128.                   gboolean   preview_mode);
  129. static void     put_pixel    (GimpDrawable *drawable,
  130.                   gint       x,
  131.                   gint       y,
  132.                   guchar    *pixel,
  133.                   gboolean   preview_mode);
  134. static gint     do_plasma    (GimpDrawable *drawable,
  135.                   gint       x1,
  136.                   gint       y1,
  137.                   gint       x2,
  138.                   gint       y2,
  139.                   gint       depth,
  140.                   gint       scale_depth,
  141.                   gboolean   preview_mode);
  142.  
  143. /***** Local vars *****/
  144.  
  145. GimpPlugInInfo PLUG_IN_INFO =
  146. {
  147.   NULL,  /* init_proc  */
  148.   NULL,  /* quit_proc  */
  149.   query, /* query_proc */
  150.   run,   /* run_proc   */
  151. };
  152.  
  153. static PlasmaValues pvals =
  154. {
  155.   0,     /* seed       */
  156.   1.0,   /* turbulence */
  157.   TRUE   /* Time seed? */
  158. };
  159.  
  160. static PlasmaInterface pint =
  161. {
  162.   FALSE     /* run */
  163. };
  164.  
  165. static guchar *work_buffer;
  166. static GtkWidget *preview;
  167.  
  168. /***** Functions *****/
  169.  
  170. MAIN ()
  171.  
  172. static void
  173. query (void)
  174. {
  175.   static GimpParamDef args[]=
  176.   {
  177.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  178.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  179.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  180.     { GIMP_PDB_INT32, "seed", "Random seed" },
  181.     { GIMP_PDB_FLOAT, "turbulence", "Turbulence of plasma" }
  182.   };
  183.   static gint nargs = sizeof (args) / sizeof (args[0]);
  184.  
  185.   gimp_install_procedure ("plug_in_plasma",
  186.               "Create a plasma cloud like image to the specified drawable",
  187.               "More help",
  188.               "Stephen Norris & (ported to 1.0 by) Eiichi Takamori",
  189.               "Stephen Norris",
  190.               "May 2000",
  191.               N_("<Image>/Filters/Render/Clouds/Plasma..."),
  192.               "RGB*, GRAY*",
  193.               GIMP_PLUGIN,
  194.               nargs, 0,
  195.               args, NULL);
  196. }
  197.  
  198. static void
  199. run (gchar   *name,
  200.      gint    nparams,
  201.      GimpParam  *param,
  202.      gint    *nreturn_vals,
  203.      GimpParam  **return_vals)
  204. {
  205.   static GimpParam values[1];
  206.   GimpDrawable *drawable;
  207.   GimpImageType drawable_type;
  208.   GimpRunModeType run_mode;
  209.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  210.  
  211.   run_mode = param[0].data.d_int32;
  212.  
  213.   *nreturn_vals = 1;
  214.   *return_vals = values;
  215.  
  216.   values[0].type = GIMP_PDB_STATUS;
  217.   values[0].data.d_status = status;
  218.  
  219.   /*  Get the specified drawable  */
  220.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  221.   drawable_type = gimp_drawable_type (param[2].data.d_drawable);
  222.  
  223.   switch (run_mode)
  224.     {
  225.     case GIMP_RUN_INTERACTIVE:
  226.       INIT_I18N_UI();
  227.       /*  Possibly retrieve data  */
  228.       gimp_get_data ("plug_in_plasma", &pvals);
  229.  
  230.       /*  First acquire information with a dialog  */
  231.       if (! plasma_dialog (drawable, drawable_type))
  232.     {
  233.       gimp_drawable_detach (drawable);
  234.       return;
  235.     }
  236.       break;
  237.  
  238.     case GIMP_RUN_NONINTERACTIVE:
  239.       INIT_I18N();
  240.       /*  Make sure all the arguments are there!  */
  241.       if (nparams != 5)
  242.     {
  243.       status = GIMP_PDB_CALLING_ERROR;
  244.     }
  245.       else
  246.     {
  247.       pvals.seed = (gint) param[3].data.d_int32;
  248.       pvals.turbulence = (gdouble) param[4].data.d_float;
  249.           pvals.timeseed = FALSE;
  250.  
  251.       if (pvals.turbulence <= 0)
  252.         status = GIMP_PDB_CALLING_ERROR;
  253.     }
  254.       break;
  255.  
  256.     case GIMP_RUN_WITH_LAST_VALS:
  257.       INIT_I18N();
  258.       /*  Possibly retrieve data  */
  259.       gimp_get_data ("plug_in_plasma", &pvals);
  260.       /* If we're using a time seed, set it at the start */
  261.       if (pvals.timeseed)
  262.         pvals.seed = time (NULL);
  263.       break;
  264.  
  265.     default:
  266.       break;
  267.     }
  268.  
  269.   if (status == GIMP_PDB_SUCCESS)
  270.     {
  271.       /*  Make sure that the drawable is gray or RGB color  */
  272.       if (gimp_drawable_is_rgb (drawable->id) || gimp_drawable_is_gray (drawable->id))
  273.     {
  274.       gimp_progress_init (_("Plasma..."));
  275.       gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
  276.  
  277.       plasma (drawable, FALSE);
  278.  
  279.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  280.         gimp_displays_flush ();
  281.  
  282.       /*  Store data  */
  283.       if (run_mode == GIMP_RUN_INTERACTIVE || 
  284.           (pvals.timeseed && run_mode == GIMP_RUN_WITH_LAST_VALS))
  285.             gimp_set_data ("plug_in_plasma", &pvals, sizeof (PlasmaValues));
  286.     }
  287.       else
  288.     {
  289.       /* gimp_message ("plasma: cannot operate on indexed color images"); */
  290.       status = GIMP_PDB_EXECUTION_ERROR;
  291.     }
  292.     }
  293.  
  294.   values[0].data.d_status = status;
  295.   gimp_drawable_detach (drawable);
  296. }
  297.  
  298. static gint
  299. plasma_dialog (GimpDrawable *drawable, GimpImageType drawable_type)
  300. {
  301.   GtkWidget *dlg;
  302.   GtkWidget *main_vbox;
  303.   GtkWidget *abox;
  304.   GtkWidget *frame;
  305.   GtkWidget *table;
  306.   GtkWidget *seed;
  307.   GtkObject *adj;
  308.  
  309.   gimp_ui_init ("plasma", TRUE);
  310.   
  311.   dlg = gimp_dialog_new (_("Plasma"), "plasma",
  312.              gimp_standard_help_func, "filters/plasma.html",
  313.              GTK_WIN_POS_MOUSE,
  314.              FALSE, TRUE, FALSE,
  315.  
  316.              _("OK"), plasma_ok_callback,
  317.              NULL, NULL, NULL, TRUE, FALSE,
  318.              _("Cancel"), gtk_widget_destroy,
  319.              NULL, 1, NULL, FALSE, TRUE,
  320.  
  321.              NULL);
  322.  
  323.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  324.               GTK_SIGNAL_FUNC (gtk_main_quit),
  325.               NULL);
  326.  
  327.   gimp_help_init ();
  328.  
  329.   main_vbox = gtk_vbox_new (FALSE, 2);
  330.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  331.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  332.   gtk_widget_show (main_vbox);
  333.  
  334.   /* make a nice preview frame */
  335.   frame = gtk_frame_new (_("Preview"));
  336.   gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
  337.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  338.   gtk_widget_show (frame);
  339.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  340.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  341.   gtk_container_add (GTK_CONTAINER (frame), abox);
  342.   gtk_widget_show (abox);
  343.   frame = gtk_frame_new (NULL);
  344.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  345.   gtk_container_add (GTK_CONTAINER (abox), frame);
  346.   gtk_widget_show (frame);
  347.   preview = preview_widget (drawable_type); /* we are here */
  348.   gtk_container_add (GTK_CONTAINER (frame), preview);
  349.  
  350.   if (pvals.timeseed)
  351.     pvals.seed = time (NULL);
  352.   plasma (drawable, TRUE); /* preview image */
  353.  
  354.   gtk_widget_show (preview);
  355.   
  356.   /*  parameter settings  */
  357.   frame = gtk_frame_new (_("Parameter Settings"));
  358.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  359.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  360.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  361.  
  362.   table = gtk_table_new (2, 3, FALSE);
  363.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  364.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  365.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  366.   gtk_container_add (GTK_CONTAINER (frame), table);
  367.  
  368.   seed = gimp_random_seed_new (&pvals.seed,
  369.                    &pvals.timeseed,
  370.                    TRUE, FALSE);
  371.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  372.                  _("Random Seed:"), 1.0, 0.5,
  373.                  seed, 1, TRUE);
  374.   gtk_signal_connect_object (GTK_OBJECT (GIMP_RANDOM_SEED_SPINBUTTON_ADJ (seed)),
  375.                  "value_changed",
  376.                  GTK_SIGNAL_FUNC (plasma_seed_changed_callback),
  377.                  (gpointer)drawable);
  378.   gtk_signal_connect_object (GTK_OBJECT (GIMP_RANDOM_SEED_TOGGLEBUTTON (seed)),
  379.                  "toggled",
  380.                  GTK_SIGNAL_FUNC (plasma_seed_changed_callback),
  381.                  (gpointer)drawable);
  382.  
  383.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  384.                   _("Turbulence:"), SCALE_WIDTH, 0,
  385.                   pvals.turbulence,
  386.                   0.1, 7.0, 0.1, 1.0, 1,
  387.                   TRUE, 0, 0,
  388.                   NULL, NULL);
  389.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  390.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  391.               &pvals.turbulence);
  392.   gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed",
  393.                  GTK_SIGNAL_FUNC (plasma_seed_changed_callback),
  394.                  (gpointer)drawable);
  395.  
  396.   gtk_widget_show (frame);
  397.   gtk_widget_show (table);
  398.   gtk_widget_show (dlg);
  399.  
  400.   gtk_main ();
  401.   gimp_help_free ();
  402.   gdk_flush ();
  403.  
  404.   return pint.run;
  405. }
  406.  
  407. static void
  408. plasma_ok_callback (GtkWidget *widget,
  409.             gpointer   data)
  410. {
  411.   pint.run = TRUE;
  412.  
  413.   gtk_widget_destroy (GTK_WIDGET (data));
  414. }
  415.  
  416. static void
  417. plasma_seed_changed_callback (GimpDrawable *drawable,
  418.                               gboolean    preview_mode)
  419. {
  420.   if (pvals.timeseed)
  421.     pvals.seed = time (NULL);
  422.   
  423.   plasma(drawable, preview_mode);
  424. }
  425.  
  426. #define AVE(n, v1, v2) n[0] = ((gint)v1[0] + (gint)v2[0]) / 2;\
  427.     n[1] = ((gint)v1[1] + (gint)v2[1]) / 2;\
  428.     n[2] = ((gint)v1[2] + (gint)v2[2]) / 2;
  429.  
  430. /*
  431.  * Some glabals to save passing too many paramaters that don't change.
  432.  */
  433.  
  434. static gint    ix1, iy1, ix2, iy2;    /* Selected image size. */
  435. static GimpTile   *tile=NULL;
  436. static gint     tile_row, tile_col;
  437. static gint     tile_width, tile_height;
  438. static gint     tile_dirty;
  439. static gint    bpp, has_alpha, alpha;
  440. static gdouble    turbulence;
  441. static glong    max_progress, progress;
  442.  
  443. /*
  444.  * The setup function.
  445.  */
  446.  
  447. static void
  448. plasma (GimpDrawable *drawable, 
  449.     gboolean    preview_mode)
  450. {
  451.   gint  depth;
  452.  
  453.   init_plasma (drawable, preview_mode);
  454.  
  455.   /*
  456.    * This first time only puts in the seed pixels - one in each
  457.    * corner, and one in the center of each edge, plus one in the
  458.    * center of the image.
  459.    */
  460.  
  461.   do_plasma (drawable, ix1, iy1, ix2 - 1, iy2 - 1, -1, 0, preview_mode);
  462.  
  463.   /*
  464.    * Now we recurse through the images, going further each time.
  465.    */
  466.   depth = 1;
  467.   while (!do_plasma (drawable, ix1, iy1, ix2 - 1, iy2 - 1, depth, 0, preview_mode))
  468.     {
  469.       depth ++;
  470.     }
  471.   end_plasma (drawable, preview_mode);
  472. }
  473.  
  474. static void
  475. init_plasma (GimpDrawable *drawable,
  476.          gboolean   preview_mode)
  477. {
  478.  
  479.   srand (pvals.seed);
  480.   turbulence = pvals.turbulence;
  481.  
  482.   if (preview_mode) 
  483.     {
  484.       ix1 = iy1 = 0;
  485.       ix2 = GTK_PREVIEW (preview)->buffer_width;
  486.       iy2 = GTK_PREVIEW (preview)->buffer_height;
  487.       bpp = GTK_PREVIEW (preview)->bpp;
  488.       alpha = bpp;
  489.       has_alpha = 0;
  490.       work_buffer = g_malloc (GTK_PREVIEW (preview)->rowstride * iy2);
  491.       memcpy (work_buffer, GTK_PREVIEW (preview)->buffer, GTK_PREVIEW (preview)->rowstride * iy2);
  492.     } 
  493.   else 
  494.     {
  495.       gimp_drawable_mask_bounds (drawable->id, &ix1, &iy1, &ix2, &iy2);
  496.       bpp = drawable->bpp;
  497.       has_alpha = gimp_drawable_has_alpha (drawable->id);
  498.       if (has_alpha)
  499.     alpha = bpp-1;
  500.       else
  501.     alpha = bpp;
  502.     }
  503.  
  504.   max_progress = (ix2 - ix1) * (iy2 - iy1);
  505.   progress = 0;
  506.  
  507.   tile_width  = gimp_tile_width ();
  508.   tile_height = gimp_tile_height ();
  509.  
  510.   tile = NULL;
  511.   tile_row = 0; tile_col = 0;
  512. }
  513.  
  514. static void
  515. provide_tile (GimpDrawable *drawable,
  516.           gint       col,
  517.           gint       row)
  518. {
  519.   if (col != tile_col || row != tile_row || !tile)
  520.     {
  521.       if (tile)
  522.     gimp_tile_unref (tile, tile_dirty);
  523.  
  524.       tile_col = col;
  525.       tile_row = row;
  526.       tile = gimp_drawable_get_tile (drawable, TRUE, tile_row, tile_col);
  527.       tile_dirty = FALSE;
  528.       gimp_tile_ref (tile);
  529.     }
  530. }
  531.  
  532. static void
  533. end_plasma (GimpDrawable *drawable,
  534.         gboolean   preview_mode)
  535. {
  536.   if (preview_mode) 
  537.     {
  538.       memcpy (GTK_PREVIEW (preview)->buffer, work_buffer, GTK_PREVIEW (preview)->rowstride * iy2);
  539.       g_free (work_buffer);
  540.       gtk_widget_queue_draw (preview);
  541.     } 
  542.   else 
  543.     {
  544.       if (tile)
  545.     gimp_tile_unref (tile, tile_dirty);
  546.       tile = NULL;
  547.  
  548.       gimp_drawable_flush (drawable);
  549.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  550.       gimp_drawable_update (drawable->id, ix1, iy1, (ix2 - ix1), (iy2 - iy1));
  551.     }
  552. }
  553.  
  554. static void
  555. get_pixel (GimpDrawable *drawable,
  556.        gint       x,
  557.        gint       y,
  558.        guchar    *pixel,
  559.        gboolean   preview_mode)
  560. {
  561.   gint   row, col;
  562.   gint   offx, offy, i;
  563.   guchar  *ptr;
  564.  
  565.   if (x < ix1)       x = ix1;
  566.   if (x > ix2 - 1)   x = ix2 - 1;
  567.   if (y < iy1)       y = iy1;
  568.   if (y > iy2 - 1)   y = iy2 - 1;
  569.  
  570.   if (preview_mode) 
  571.     {
  572.       memcpy (pixel, work_buffer + (y * GTK_PREVIEW (preview)->rowstride) + (x * bpp), bpp);
  573.     }
  574.   else 
  575.     {
  576.       col = x / tile_width;
  577.       row = y / tile_height;
  578.       offx = x % tile_width;
  579.       offy = y % tile_height;
  580.       
  581.       provide_tile (drawable, col, row);
  582.       ptr = tile->data + (offy * tile->ewidth + offx) * bpp;
  583.  
  584.       for (i = 0; i < alpha; i++)
  585.     pixel[i] = ptr[i];
  586.     }
  587. }
  588.  
  589. static void
  590. put_pixel (GimpDrawable *drawable,
  591.        gint       x,
  592.        gint       y,
  593.        guchar    *pixel,
  594.        gboolean   preview_mode)
  595. {
  596.   gint   row, col;
  597.   gint   offx, offy, i;
  598.   guchar  *ptr;
  599.  
  600.   if (x < ix1)       x = ix1;
  601.   if (x > ix2 - 1)   x = ix2 - 1;
  602.   if (y < iy1)       y = iy1;
  603.   if (y > iy2 - 1)   y = iy2 - 1;
  604.  
  605.   if (preview_mode)
  606.     memcpy (work_buffer + (y * GTK_PREVIEW (preview)->rowstride) + (x * bpp), pixel, bpp);
  607.   else
  608.     {
  609.       col = x / tile_width;
  610.       row = y / tile_height;
  611.       offx = x % tile_width;
  612.       offy = y % tile_height;
  613.  
  614.       provide_tile (drawable, col, row);
  615.       ptr = tile->data + (offy * tile->ewidth + offx) * bpp;
  616.  
  617.       for (i = 0; i < alpha; i++)
  618.     ptr[i] = pixel[i];
  619.  
  620.       if (has_alpha)
  621.     ptr[alpha] = 255;
  622.  
  623.       tile_dirty = TRUE;
  624.       progress++;
  625.     }
  626. }
  627.  
  628. static void
  629. random_rgb (guchar *d)
  630. {
  631.   gint i;
  632.  
  633.   for(i = 0; i < alpha; i++)
  634.     {
  635.       d[i] = rand() % 256;
  636.     }
  637. }
  638.  
  639. static void
  640. add_random (guchar *d,
  641.         gint    amnt)
  642. {
  643.   gint i, tmp;
  644.  
  645.   for (i = 0; i < alpha; i++)
  646.     {
  647.       if (amnt == 0)
  648.     {
  649.       amnt = 1;
  650.     }
  651.       tmp = amnt/2 - rand() % amnt;
  652.  
  653.       if ((gint)d[i] + tmp < 0)
  654.     {
  655.       d[i] = 0;
  656.     }
  657.       else if ((gint)d[i] + tmp > 255)
  658.     {
  659.       d[i] = 255;
  660.     }
  661.       else
  662.     {
  663.       d[i] += tmp;
  664.     }
  665.     }
  666. }
  667.  
  668. static gint
  669. do_plasma (GimpDrawable *drawable,
  670.        gint       x1,
  671.        gint       y1,
  672.        gint       x2,
  673.        gint       y2,
  674.        gint       depth,
  675.        gint       scale_depth,
  676.        gboolean   preview_mode)
  677. {
  678.   guchar  tl[3], ml[3], bl[3], mt[3], mm[3], mb[3], tr[3], mr[3], br[3];
  679.   guchar  tmp[3];
  680.   gint    ran;
  681.   gint    xm, ym;
  682.  
  683.   static gint count = 0;
  684.  
  685.   /* Initial pass through - no averaging. */
  686.  
  687.   if (depth == -1)
  688.     {
  689.       random_rgb (tl);
  690.       put_pixel (drawable, x1, y1, tl, preview_mode);
  691.       random_rgb (tr);
  692.       put_pixel (drawable, x2, y1, tr, preview_mode);
  693.       random_rgb (bl);
  694.       put_pixel (drawable, x1, y2, bl, preview_mode);
  695.       random_rgb (br);
  696.       put_pixel (drawable, x2, y2, br, preview_mode);
  697.       random_rgb (mm);
  698.       put_pixel (drawable, (x1 + x2) / 2, (y1 + y2) / 2, mm, preview_mode);
  699.       random_rgb (ml);
  700.       put_pixel (drawable, x1, (y1 + y2) / 2, ml, preview_mode);
  701.       random_rgb (mr);
  702.       put_pixel (drawable, x2, (y1 + y2) / 2, mr, preview_mode);
  703.       random_rgb (mt);
  704.       put_pixel (drawable, (x1 + x2) / 2, y1, mt, preview_mode);
  705.       random_rgb (ml);
  706.       put_pixel (drawable, (x1 + x2) / 2, y2, ml, preview_mode);
  707.  
  708.       return 0;
  709.     }
  710.  
  711.   /*
  712.    * Some later pass, at the bottom of this pass,
  713.    * with averaging at this depth.
  714.    */
  715.   if (depth == 0)
  716.     {
  717.       gdouble    rnd;
  718.       gint    xave, yave;
  719.  
  720.       get_pixel (drawable, x1, y1, tl, preview_mode);
  721.       get_pixel (drawable, x1, y2, bl, preview_mode);
  722.       get_pixel (drawable, x2, y1, tr, preview_mode);
  723.       get_pixel (drawable, x2, y2, br, preview_mode);
  724.  
  725.       rnd = (256.0 / (2.0 * (gdouble)scale_depth)) * turbulence;
  726.       ran = rnd;
  727.  
  728.       xave = (x1 + x2) / 2;
  729.       yave = (y1 + y2) / 2;
  730.  
  731.       if (xave == x1 && xave == x2 && yave == y1 && yave == y2)
  732.     {
  733.       return 0;
  734.     }
  735.  
  736.       if (xave != x1 || xave != x2)
  737.     {
  738.       /* Left. */
  739.       AVE (ml, tl, bl);
  740.       add_random (ml, ran);
  741.       put_pixel (drawable, x1, yave, ml, preview_mode);
  742.  
  743.       if (x1 != x2)
  744.         {
  745.                 /* Right. */
  746.           AVE (mr, tr, br);
  747.           add_random (mr, ran);
  748.           put_pixel (drawable, x2, yave, mr, preview_mode);
  749.         }
  750.     }
  751.  
  752.       if (yave != y1 || yave != y2)
  753.     {
  754.       if (x1 != xave || yave != y2)
  755.         {
  756.           /* Bottom. */
  757.           AVE (mb, bl, br);
  758.           add_random (mb, ran);
  759.           put_pixel (drawable, xave, y2, mb, preview_mode);
  760.         }
  761.  
  762.       if (y1 != y2)
  763.         {
  764.           /* Top. */
  765.           AVE (mt, tl, tr);
  766.           add_random (mt, ran);
  767.           put_pixel (drawable, xave, y1, mt, preview_mode);
  768.         }
  769.     }
  770.  
  771.       if (y1 != y2 || x1 != x2)
  772.     {
  773.       /* Middle pixel. */
  774.       AVE (mm, tl, br);
  775.       AVE (tmp, bl, tr);
  776.       AVE (mm, mm, tmp);
  777.  
  778.       add_random (mm, ran);
  779.       put_pixel (drawable, xave, yave, mm, preview_mode);
  780.     }
  781.  
  782.       count ++;
  783.  
  784.       if (!(count % 2000) && !preview_mode)
  785.     {
  786.       gimp_progress_update ((double) progress / (double) max_progress);
  787.     }
  788.  
  789.       if ((x2 - x1) < 3 && (y2 - y1) < 3)
  790.     {
  791.       return 1;
  792.     }
  793.       return 0;
  794.     }
  795.  
  796.   xm = (x1 + x2) >> 1;
  797.   ym = (y1 + y2) >> 1;
  798.  
  799.   /* Top left. */
  800.   do_plasma (drawable, x1, y1, xm, ym, depth - 1, scale_depth + 1, preview_mode);
  801.   /* Bottom left. */
  802.   do_plasma (drawable, x1, ym, xm ,y2, depth - 1, scale_depth + 1, preview_mode);
  803.   /* Top right. */
  804.   do_plasma (drawable, xm, y1, x2 , ym, depth - 1, scale_depth + 1, preview_mode);
  805.   /* Bottom right. */
  806.   return do_plasma (drawable, xm, ym, x2, y2, depth - 1, scale_depth + 1, preview_mode);
  807. }
  808.  
  809.  
  810. /* preview library */
  811.  
  812.  
  813. static GtkWidget *
  814. preview_widget (GimpImageType drawable_type)
  815. {
  816.   GtkWidget *preview;
  817.   guchar    *buf;
  818.   gint       y;
  819.  
  820.   if (drawable_type == GIMP_GRAY_IMAGE || 
  821.            drawable_type == GIMP_GRAYA_IMAGE)
  822.   {
  823.     preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE);
  824.     buf = g_malloc0 (PREVIEW_SIZE);
  825.   }
  826.   else /* Gray & colour are the only possibilities here */
  827.   {
  828.     preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  829.     buf = g_malloc0 (PREVIEW_SIZE * 3);
  830.   }
  831.  
  832.   gtk_preview_size (GTK_PREVIEW (preview), PREVIEW_SIZE, PREVIEW_SIZE);
  833.   
  834.   for (y = 0; y < PREVIEW_SIZE; y++) 
  835.     gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, y, PREVIEW_SIZE);
  836.   
  837.   g_free (buf);
  838.   
  839.   return preview;
  840. }
  841.  
  842.